/*
 * common_utilits.h
 *
 *  Created on: 2016年1月7日
 *      Author: guyadong
 */

#ifndef COMMON_SOURCE_CPP_COMMON_UTILITS_H_
#define COMMON_SOURCE_CPP_COMMON_UTILITS_H_
#include <cstring>
#include <string>
#include <memory>
#include <list>
#include <vector>
#include <algorithm>
#include <type_traits>
#include <stdexcept>
#include <assert.h>
#include <string_utils.h>
namespace gdface {
inline  namespace com_utilits{
inline char hex_to_byte(char c){
	if(c>='0' && c<='9')return c-'0';
	else if(c>='a' && c<='f')return c-'a'+10;
	else if(c>='A' && c<='F')return c-'A'+10;
	else
		throw std::invalid_argument("invalid hex char[0-9a-fA-F]");
}
inline void hex_to_bytes(const char* hex_str, void *out, size_t size) {
	static const std::string err_invalid_hex_str="the argument hex_str is not a valid hex string";
	if (nullptr==hex_str||nullptr == out)
		throw std::invalid_argument("the argument 'hex_str' and 'bytes' must not be null");
	auto len=strlen(hex_str);
	if (0==len||(len&1))
		throw std::invalid_argument(err_invalid_hex_str);
	auto limit = std::min(len >> 1, size) << 1;
	try{
		auto bytes=reinterpret_cast<uint8_t*>(out);
		for (auto i = 0; i < limit; i += 2) {
			bytes[i >> 1] = (hex_to_byte(hex_str[i]) << 4) + hex_to_byte(hex_str[i + 1]);
		}
	}catch(std::invalid_argument &e){
		throw std::invalid_argument(std::string(err_invalid_hex_str).append(" because:").append(e.what()));
	}
}

inline std::vector<uint8_t> hex_to_bytes(const char* hex_str) {
	std::vector<uint8_t> v(strlen(hex_str) >> 1);
	hex_to_bytes(hex_str, v.data(), v.size());
	return std::move(v);
}
inline std::vector<uint8_t> hex_to_bytes(const std::string &hex_str) {
	return hex_to_bytes(hex_str.data());
}
inline void bytes_to_hex(const void *in, size_t size, char* hex_str, size_t limit) {
	const static char hex_char[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
	if (nullptr == in || nullptr == hex_str)
		throw std::invalid_argument("the argument 'bytes' and 'hex_str' must not be null");
	if (limit < size << 1)
		throw std::invalid_argument("the capacity of out buffer  'hex_str' can't fit size of input ");
	auto bytes=reinterpret_cast<const uint8_t*>(in);
	for (decltype(size) i = 0; i < size; ++i) {
		hex_str[i << 1] = hex_char[bytes[i] >> 4]; // 高四位
		hex_str[(i << 1) + 1] = hex_char[bytes[i] & 0x0f]; // 低四位
	}
}
inline std::vector<char> bytes_to_hex(const void *bytes, size_t size) {
	std::vector<char> v((size << 1) + 1);
	bytes_to_hex(bytes, size, v.data(), v.size());
	v[size << 1] = 0;
	return std::move(v);
}
inline std::vector<char> bytes_to_hex(const std::vector<uint8_t> &v) {
	return bytes_to_hex(v.data(), v.size());
}
inline std::string bytes_to_hex_string(const void *bytes, size_t size) {
	return std::string(bytes_to_hex(bytes, size).data());
}
inline std::string bytes_to_hex_string(const std::vector<uint8_t> &v) {
	return bytes_to_hex_string(v.data(), v.size());
}
inline void bit_set(void *in, size_t size, int index)
{
	if (nullptr == in)
		throw std::invalid_argument("the argument 'in' must not be null");
	auto byteIndex = size - 1 - (index >> 3);
	if (byteIndex < 0 || byteIndex >= size)
		throw std::invalid_argument("the bit index is out of range");
	auto bytes = reinterpret_cast<uint8_t *>(in);
	bytes[byteIndex] |= (1 << (index & 0x07));
}
inline void bit_clear(void *in, size_t size, int index)
{
	if (nullptr == in)
		throw std::invalid_argument("the argument 'in' must not be null");
	auto byteIndex = size - 1 - (index >> 3);
	if (byteIndex < 0 || byteIndex >= size)
		throw std::invalid_argument("the bit index is out of range");
	auto bytes = reinterpret_cast<uint8_t *>(in);
	bytes[byteIndex] &= ~(1 << (index & 0x07));
}
inline bool bit_check(const void *in, size_t size, int index)
{
	if (nullptr == in)
		throw std::invalid_argument("the argument 'in' must not be null");
	auto byteIndex = size - 1 - (index >> 3);
	if (byteIndex < 0 || byteIndex >= size)
		throw std::invalid_argument("the bit index is out of range");
	auto bytes = reinterpret_cast<const uint8_t *>(in);
	return (bytes[byteIndex] & (1 << (index & 0x07))) != 0;
}
inline void bit_set(void *in, size_t size, int index, bool isSet)
{
	if(isSet){
		bit_set(in, size, index);
	}else{
		bit_set(in, size, index);
	}
}
inline void bit_set(std::vector<uint8_t> &in, int index)
{
	bit_set(in.data(), in.size(), index);
}
inline void bit_clear(std::vector<uint8_t> &in, int index){
	bit_clear(in.data(), in.size(), index);
}
inline void bit_set(std::vector<uint8_t> &in, int index, bool isSet){
	bit_set(in.data(), in.size(), index, isSet);
}
inline bool bit_check(const std::vector<uint8_t> &in, int index){
	return bit_check(in.data(), in.size(), index);
}
//************************************
// 将4字节的IP地址转为.分割十进制的标准IP地址字符串(如'192.168.0.1'),如果输入的字符串非4字节长度返回'0.0.0.0'
// @param    const std::string & byte4
// @return   std::string
//************************************
inline std::string format_ip(const std::string& byte4)
{
	if (byte4.size() != 4)
	{
		return "0.0.0.0";
	}
	std::stringstream ss;
	int c = 0;
	for_each(byte4.begin(), byte4.end(), [&](char ch) {
		if (c++) {
			ss << ".";
		}
		ss << ((uint32_t)ch & 0xff);
	});
	return std::move(ss.str());
}
//************************************
// 将输入的.分割十进制的标准IP地址字符串(如'192.168.0.1')转为4字节数组,如果输入格式不为.分隔的4节字符,返回空字符串
// @param    const std::string & ipstr
// @return   std::string
//************************************
inline std::string parse_ip(const std::string& ipstr)
{
	if (std::regex_match(ipstr, std::regex("^((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))$")))
	{
		uint8_t num[] = { 0,0,0,0 };
		auto four = split(ipstr, "\\.");
		if (4 == four.size()) {
			int c = 0;
			std::for_each(four.begin(), four.end(), [&](const std::string&e) {
				num[c++] = (uint8_t)atoi(e.c_str());
			});
		}
		return std::string((char*)num, sizeof(num));
	}
	return "";
}
//************************************
// 将6字节的MAC地址转为:分割十六进制的标准MAC地址字符串(如'd0:17:c2:d0:3f:bf'),如果输入格式不正确返回'00.00.00.00.00.00'
// @param    const std::string & byte6
// @param    const std::string & delim 分割符,默认:
// @return   std::string
//************************************
inline std::string format_mac(const std::string& byte6, const std::string &delim = ":")
{
	if (byte6.size() != 6)
	{
		return "00.00.00.00.00.00";
	}
	std::stringstream ss;
	int c = 0;
	std::for_each(byte6.begin(), byte6.end(), [&](char ch) {
		if (c++) {
			ss << delim;
		}
		ss << std::hex << ((uint32_t)ch & 0xff);
	});
	return ss.str();
}
//************************************
// 将输入的:或-分割(或无分割符)十六进制的标准MAC地址字符串(如'D0:17:C2:D0:3F:BF')转为6字节数组,如果输入格式不正确,返回空字符串
// @param    const std::string & input
// @return   std::string
//************************************
inline std::string parse_mac(const std::string& input)
{
	if (std::regex_match(input, std::regex("^([a-fA-F0-9]{2}[:-]?){5}[a-fA-F0-9]{2}$")))
	{
		auto cleaned = std::regex_replace(input, std::regex("[-:]"), "");
		auto byte6 = hex_to_bytes(cleaned);
		return std::string((char*)byte6.data(), byte6.size());
	}
	return "";
}
//************************************
// 将输入的字符串转为int,如果输入格式不正确,返回nullptr
// @param    const std::string & input
// @return   std::shared_ptr<int>
//************************************
inline std::shared_ptr<int> parse_int(const std::string& input)
{
	if (std::regex_match(input, std::regex("^[-+]?\\d{1,10}$")))
	{
		return std::make_shared<int>(std::atoi(input.c_str()));
	}
	return nullptr;
}
//************************************
// 将输入的字符串转为float,如果输入格式不正确,返回nullptr
// @param    const std::string & input
// @return   std::shared_ptr<float>
//************************************
inline std::shared_ptr<double> parse_float(const std::string& input)
{
	if (std::regex_match(input, std::regex("^[-+]?(\\d*\\.\\d+|\\d+)$")))
	{
		return std::make_shared<double>(std::atof(input.c_str()));
	}
	return nullptr;
}
//************************************
// 将输入的字符串转为bool,如果输入格式不正确,返回nullptr
// @param    const std::string & input
// @return   std::shared_ptr<float>
//************************************
inline std::shared_ptr<bool> parse_bool(const std::string& input)
{
	if (std::regex_match(input, std::regex("^(true|false|1|0|on|off|yes|no)$", std::regex::icase)))
	{
		auto b = std::regex_match(input, std::regex("^(true|1|on|yes)$", std::regex::icase));
		return std::make_shared<bool>(b);
	}
	return nullptr;
}
//************************************
// 将输入的字符串转为int,如果输入格式不正确,返回nullptr
// @param    const std::string & input
// @return   std::shared_ptr<std::list<int>> 解析的数字列表
//************************************
inline std::shared_ptr<std::list<int>> parse_int_list(const std::string& input)
{
	if (std::regex_match(input, std::regex("^[\\s,;:]*(([-+]?\\d+)[\\s,;:]+([-+]?\\d+)?)+$")))
	{
		std::list<int> parsed;
		std::vector<std::string> nums;
		const std::regex ws_re("[-+]?\\d{1,10}"); // whitespace
		std::copy(std::sregex_token_iterator(input.begin(), input.end(), ws_re, 0),
			std::sregex_token_iterator(),
			std::inserter(nums, nums.begin()));
		std::transform(nums.begin(), nums.end(), std::inserter(parsed, parsed.begin()), [](const std::string &n) {
			auto p = parse_int(n);
			assert(p);
			return *p;
		});
		if (!parsed.empty()) {
			return std::make_shared<std::list<int>>(parsed);
		}
	}
	return nullptr;
}
} /* namespace com_utilits */

}  /* namespace gdface */

#endif /* COMMON_SOURCE_CPP_COMMON_UTILITS_H_ */
